package de.tabuma.lib.webservice.client;

import de.tabuma.webservice.ObjectMethods;
import java.io.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.logging.*;
import java.net.*;

/**
 * @author $Author: alefen $
 * @version $Revision: 1.1.1.1.2.1.4.1 $
 * @since $Date: 2010/01/13 10:14:21 $
 */
public class ExecuteMethod {
    private static Logger log = Logger.getLogger(ExecuteMethod.class.getName());
    private static int maxConnectionTrials = 3;
    public static Object executeMethod(String methodName, String soapAction, String serverUrl, Object params[], Class returnType, Class returnType1, int count) throws Exception {
        Object obj = null;
        try {
            URL wsdlUrl = new URL(serverUrl);
            HttpURLConnection conn = (HttpURLConnection) wsdlUrl.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            conn.setDoInput (true);
            conn.setDoOutput (true);
            conn.setUseCaches (false);
            conn.setAllowUserInteraction(true);
            conn.setInstanceFollowRedirects(false);
            conn.setRequestProperty ("Content-Type","text/xml; charset=UTF-8");
            conn.setRequestProperty("SoapAction", "\"" + soapAction + "\"");
            String xml1 = getSoapText(methodName, params);
            String xml = getMessageContent(xml1);

            PrintStream outStream = new PrintStream(conn.getOutputStream());
            outStream.print(new String(xml.getBytes("UTF-8"), "ISO-8859-1"));
            outStream.close();
            
            BufferedReader inStream = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String response = "";
            String str = "";
            while ((str = inStream.readLine())!=null) {
                response += str;
            }
            inStream.close();
            if(returnType!=null) {
                if(response.indexOf("class java.lang.NullPointerException")!=-1) {
                    int index1 = response.indexOf("<ExceptionMessage>");
                    int index2 = response.indexOf("</ExceptionMessage>");
                    String exceptionMessage = response.substring(index1+"<ExceptionMessage>".length(),index2);
                    IOException ioe = new IOException("SOAP Service calls exception:"+exceptionMessage);
                    throw ioe;
                }
                obj = parseContent(response, returnType, returnType1, methodName);
            }
        }
        catch(IOException e) {
            if(count<maxConnectionTrials) {
                return executeMethod(methodName, soapAction, serverUrl, params, returnType, returnType1, count+1);
            }
            else {
                throw new Exception(e);
            }
        }
        catch(Exception e) {
            String warning = e.getMessage()+"/"+e.getCause()+"/"+e.getClass()+"\n";
            for(int i=0;i<e.getStackTrace().length;i++) {
                warning += e.getStackTrace()[i]+"\n";
            }
            log.warning(warning);
        }
        return obj;
    }
    public static Object executeMethod(String methodName, String soapAction, String serverUrl, Object params[], Class returnType, Class returnType1) {
        try {
            return executeMethod(methodName, soapAction, serverUrl, params, returnType, returnType1, 0);
        }
        catch(Exception e) {
            String warning = e.getMessage()+"/"+e.getCause()+"/"+e.getClass()+"\n";
            for(int i=0;i<e.getStackTrace().length;i++) {
                warning += e.getStackTrace()[i]+"\n";
            }
            log.warning(warning);
        }
        return null;
    }
    
    public static String getMessageContent(String xml1) {
        try {
            String xml = "";
            String xmlBeginn = "";
            xmlBeginn += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
            xmlBeginn += "<soapenv:Envelope xsi:schemaLocation=\"http://schemas.xmlsoap.org/soap/envelope/ http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:tns=\"www.tabuma.de/sso\">\n<soapenv:Body>";

            String xmlEnd = "</soapenv:Body>\n</soapenv:Envelope>";

            xml = xmlBeginn +"\n"+xml1+xmlEnd;
            return xml;
        }
        catch(Exception e) {
            String warning = e.getMessage()+"/"+e.getCause()+"/"+e.getClass()+"\n";
            for(int i=0;i<e.getStackTrace().length;i++) {
                warning += e.getStackTrace()[i]+"\n";
            }
            log.warning(warning);
        }
        return null;
    }
    
    public static String getSoapText(String method, Object object[]) {
        String str = "";
        try {

            str += "<tns:"+method+">\n";
            str += "<tns:Request_"+method+">\n";

            for(int i=0;i<object.length;i++) {
                Object obj = object[i];
                if(obj.getClass().isPrimitive()) {
                    str += "<"+obj.getClass().getName()+(i+1)+">"+obj+"</"+obj.getClass().getName()+(i+1)+">\n";
                }
                else {
                    String obj1 = obj.getClass().getSimpleName();
                    if(obj1.equals("String")) {
                        str += "<"+obj.getClass().getSimpleName()+(i+1)+">"+obj+"</"+obj.getClass().getSimpleName()+(i+1)+">\n";
                    }
                    else if(obj1.equals("Integer")) {
                        str += "<int"+(i+1)+">"+obj+"</int"+(i+1)+">\n";
                    }
                    else if(obj1.equals("Long")) {
                        str += "<long"+(i+1)+">"+obj+"</long"+(i+1)+">\n";
                    }
                    else if(obj1.equals("Double")) {
                        str += "<double"+(i+1)+">"+obj+"</double"+(i+1)+">\n";
                    }
                    else if(obj1.equals("Boolean")) {
                        str += "<boolean"+(i+1)+">"+obj+"</boolean"+(i+1)+">\n";
                    }
                    else {
                        str += "<"+obj1+(i+1)+">\n";
                        for(int j=0;j<obj.getClass().getDeclaredFields().length;j++) {
                            Field field = obj.getClass().getDeclaredFields()[j];
                            String getMethod = ObjectMethods.getGetter(field.getName());
                            Object value = obj.getClass().getMethod(getMethod).invoke(obj);
                            str += "<"+field.getName()+">"+value+"</"+field.getName()+">\n";
                        }
                        str += "</"+obj1+(i+1)+">\n";
                    }
                }
            }
            str += "</tns:Request_"+method+">\n";
            str += "</tns:"+method+">\n";
            log.warning(method+"/"+str);
        }
        catch(Exception e) {
            String warning = e.getMessage()+"/"+e.getCause()+"/"+e.getClass()+"\n";
            for(int i=0;i<e.getStackTrace().length;i++) {
                warning += e.getStackTrace()[i]+"\n";
            }
            log.warning(warning);
        }
        return str;
    }
    
    public static Object parseContent(String returnString, Class returnType, Class returnType1, String methodName) throws Exception {
        Object obj = null;
        log.warning(methodName+"/"+returnString);
        String method = "tns:Response_"+methodName;
        int index1 = returnString.indexOf("<"+method+">");
        int index2 = returnString.indexOf("</"+method+">");
        String difference = returnString.substring(index1+2+method.length(),index2);
        obj = parse(difference, returnType, returnType1);
        return obj;
    }
    
    public static Object parse(String returnString, Class returnType, Class returnType1) throws Exception {

        if(returnType.getName().equals("java.lang.String")) {
            Object obj = new String();
            String string = "string";
            int index1 = returnString.indexOf("<"+string+">");
            int index2 = returnString.indexOf("</"+string+">");
            String response = returnString.substring(index1+2+string.length(), index2);
            obj = response;
            return obj;
        }

        if(returnType.getName().equals("java.lang.Integer")) {
            String string = "int";
            int index1 = returnString.indexOf("<"+string+">");
            int index2 = returnString.indexOf("</"+string+">");
            String response = returnString.substring(index1+2+string.length(), index2);
            Integer valueOf = Integer.valueOf(response);
            return valueOf;
        }

        if(returnType.getName().equals("java.lang.Long")) {
            String string = "long";
            int index1 = returnString.indexOf("<"+string+">");
            int index2 = returnString.indexOf("</"+string+">");
            String response = returnString.substring(index1+2+string.length(), index2);
            Long valueOf = Long.valueOf(response);
            return valueOf;
        }

        if(returnType.getName().equals("java.lang.Double")) {
            String string = "double";
            int index1 = returnString.indexOf("<"+string+">");
            int index2 = returnString.indexOf("</"+string+">");
            String response = returnString.substring(index1+2+string.length(), index2);
            Double valueOf = Double.valueOf(response);
            return valueOf;
        }
        
        if(returnType.isPrimitive()) {
            Object obj = returnType.getDeclaredConstructors()[0].newInstance();
            String string = returnType.getName();
            int index1 = returnString.indexOf("<"+string+">");
            int index2 = returnString.indexOf("</"+string+">");
            String response = returnString.substring(index1+2+string.length(), index2);
            obj = response;
            return obj;
        }

        if(returnType.isArray() || returnType.isEnum() || returnType.getSimpleName().equals("List")) {
            List list = new ArrayList();
            String string = returnType1.getSimpleName();

            int index1 = returnString.indexOf("<"+string+">");
            int index2 = returnString.indexOf("</"+string+">");
            while(index1!=-1 && index2!=-1) {
                String response = returnString.substring(index1+2+string.length(), index2);
                Object object = parse(response, returnType1, null);
                list.add(object);
                returnString = returnString.substring(index2 + ("</"+string+">").length(), returnString.length());
                index1 = returnString.indexOf("<"+string+">");
                index2 = returnString.indexOf("</"+string+">");
            }
            return list;
        }

        Object obj = returnType.newInstance();
        for(int i=0;i<returnType.getDeclaredFields().length;i++) {
            Field myField = returnType.getDeclaredFields()[i];
            String name = myField.getName();
            String setMethodName = ObjectMethods.getSetter(name);
            int index1 = returnString.indexOf("<"+name+">");
            int index2 = returnString.indexOf("</"+name+">");
            String value = returnString.substring(index1 + ("<"+name+">").length(), index2);
            boolean found = false;
            for(int j=0;j<obj.getClass().getDeclaredMethods().length;j++) {
                Method method = obj.getClass().getDeclaredMethods()[j];
                if(method.getName().equals(setMethodName)) {
                    if(value==null) {
                        value = "0";
                    }
                    if(myField.getType().getName().equals("int") || myField.getType().getSimpleName().equals("Integer")) {
                        Integer intValue = Integer.valueOf(value);
                        method.invoke(obj, intValue);
                    }
                    if(myField.getType().getName().equals("double") || myField.getType().getSimpleName().equals("Double")) {
                        Double doubleValue = Double.valueOf(value);
                        method.invoke(obj, doubleValue);
                    }
                    if(myField.getType().getSimpleName().equals("Boolean")) {
                        Boolean booleanValue = Boolean.valueOf(value);
                        method.invoke(obj, booleanValue);
                    }
                    if(myField.getType().getName().equals("long") || myField.getType().getSimpleName().equals("Long")) {
                        Long longValue = Long.valueOf(value);
                        method.invoke(obj, longValue);
                    }
                    if(myField.getType().getSimpleName().equals("String")) {
                        method.invoke(obj, value);
                    }
                    j = obj.getClass().getDeclaredMethods().length;
                    found = true;
                }
            }
            if(!found) {
                log.warning(setMethodName + " not found!");
            }
        }
        return obj;
    }

    public static void main(String args[]) {
        try {
            String xml = "<html><body>Änderung</body></html>";
            String myString = new String(xml.getBytes("UTF-8"),"ISO-8859-1");
            System.out.println(myString);

            String myString1 = new String(myString.getBytes("ISO-8859-1"),"UTF-8");
            System.out.println(myString1);

        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }
}